package com.mysoft.gfyx.clue.service.impl;

import com.alibaba.excel.EasyExcel;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.mysoft.framework.api.document.DocumentProvider;
import com.mysoft.framework.common.exception.BusinessLogicException;
import com.mysoft.framework.context.api.ContextManager;
import com.mysoft.framework.context.info.ContextInfo;
import com.mysoft.framework.sdk.system.api.SystemDataProvider;
import com.mysoft.framework.sdk.system.dto.UserDTO;
import com.mysoft.gfyx.clue.controller.dto.Perm.GetUserBUDataPermissionResponseDto;
import com.mysoft.gfyx.clue.controller.dto.Perm.GetUserAreaPermissionResponseDto;
import com.mysoft.gfyx.clue.controller.dto.Perm.ImportUserBUDataPermissionRequestDto;
import com.mysoft.gfyx.clue.controller.dto.Perm.ImportUserBUDataPermissionResponseDto;
import com.mysoft.gfyx.clue.dao.PermBUDao;
import com.mysoft.gfyx.clue.dao.PermTypeDao;
import com.mysoft.gfyx.clue.dao.PermUserDao;
import com.mysoft.gfyx.clue.dao.entity.PermBU;
import com.mysoft.gfyx.clue.dao.entity.PermType;
import com.mysoft.gfyx.clue.dao.entity.PermUser;
import com.mysoft.gfyx.clue.remoteservice.RemoteAreaService;
import com.mysoft.gfyx.clue.remoteservice.RemoteProfitService;
import com.mysoft.gfyx.clue.remoteservice.RemoteSystemIBasicPublicService;
import com.mysoft.gfyx.clue.remoteservice.dto.*;
import com.mysoft.gfyx.clue.service.DataPermissionService;
import com.mysoft.gfyx.common.dto.RequestDto;
import com.mysoft.gfyx.common.dto.SystemQueryUser.QueryUserResponseDto;
import com.mysoft.gfyx.common.dto.SystemQueryUserBusinessUnit.ResponseDto;
import com.mysoft.gfyx.common.dto.SystemQueryOrganization.QueryOrganizationResponseDto;
import com.mysoft.gfyx.common.rpc.opptyservice.OpptyServiceClientFactoryService;
import com.mysoft.gfyx.common.rpc.opptyservice.OpptyServiceClientService;
import com.mysoft.gfyx.common.rpc.opptyservice.dto.BaseOrgAreaRequestDto;
import com.mysoft.gfyx.common.util.QueryParamUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class DataPermissionServiceImp implements DataPermissionService {

    @Autowired
    private PermBUDao permBUDao;

    @Autowired
    private PermTypeDao permTypeDao;

    @Autowired
    private PermUserDao permUserDao;

    @Autowired
    private RemoteSystemIBasicPublicService remoteSystemIBasicPublicService;

    @Autowired
    private RemoteAreaService remoteAreaService;

    @Resource
    private ContextManager contextManager;
    @Resource
    private SystemDataProvider systemDataProvider;
    @Resource
    private DocumentProvider documentProvider;

    @Autowired
    private RemoteProfitService remoteProfitService;

    @Autowired
    private OpptyServiceClientFactoryService opptyServiceClientFactoryService;

    public void saveBUDataPermission(UUID permTypeGUID, UUID BUGUID, BUDataPermissionType filterType, String filterValue) {
        PermBU permBU = new PermBU();
        permBU.setPermTypeGUID(permTypeGUID);
        permBU.setBUGUID(BUGUID);
        permBU.setFilterType(filterType.toString());
        permBU.setFilterValue(filterValue);
        savePermBU(permBU);
    }

    public PermType getPermType(DataPermissionType filterType) {
        QueryWrapper<PermType> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("TypeCode", filterType.toString());
        queryWrapper.last("limit 1");

        PermType permType = permTypeDao.selectOne(queryWrapper);

        if (permType == null) {
            throw new BusinessLogicException("找不到指定的数据集");
        }
        return permType;
    }

    protected void savePermBU(PermBU permBU) {
        QueryWrapper<PermBU> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("BUGUID", permBU.getBUGUID());
        queryWrapper.eq("PermTypeGUID", permBU.getPermTypeGUID());
        queryWrapper.last("limit 1");

        PermBU permBUDB = permBUDao.selectOne(queryWrapper);

        if (permBUDB == null) {
            permBU.setPermBUGUID(UUID.randomUUID());
            permBUDao.insert(permBU);
        } else {
            permBU.setPermBUGUID(permBUDB.getPermBUGUID());
            permBUDao.updateById(permBU);
        }
    }

    public void saveBUDataManager(UUID BUGUID, UUID permTypeGUID, List<UUID> UsersGUID) {
        // 1) 删除现有的负责人
        QueryWrapper<PermUser> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("ManagedBUGUID", BUGUID.toString());
        permUserDao.delete(queryWrapper);

        // 2) 添加新的负责人
        List<PermUser> permUsers = new LinkedList<>();
        UsersGUID.forEach(u -> {
            PermUser permUser = new PermUser();
            permUser.setPermUserGUID(UUID.randomUUID());
            permUser.setUserGUID(u);
            permUser.setManagedBUGUID(BUGUID);
            permUser.setPermTypeGUID(permTypeGUID);

            permUsers.add(permUser);
        });

        permUserDao.insertBatchWithDynamicExt(permUsers);
    }

    public void saveUserBUDataPermission(DataPermissionType dataPermissionType,
                                         UUID BUGUID,
                                         BUDataPermissionType filterType,
                                         String filterValue,
                                         List<UUID> UsersGUID) {
        PermType permType = getPermType(dataPermissionType);

        saveBUDataPermission(permType.getPermTypeGUID(), BUGUID, filterType, filterValue);

        saveBUDataManager(BUGUID, permType.getPermTypeGUID(), UsersGUID);

        // 同步到供方影响
        syncBuAreaPermission(BUGUID.toString(), filterValue, UsersGUID);
    }

    private void syncBuAreaPermission(String buGuid, String areaCodes, List<UUID> userIds) {
        OpptyServiceClientService opptyService = opptyServiceClientFactoryService.getOpptyServiceClientService();
        BaseOrgAreaRequestDto dto = new BaseOrgAreaRequestDto();
        dto.setOrgGuid(buGuid);
        List<String> areaCodeList = Arrays.asList(areaCodes.split(","));
        dto.setAreaCodes(areaCodeList);
        dto.setUserGuids(userIds);
        Object res = opptyService.syncOrgAreaPermission(dto);
        System.out.println(res);
    }

    public GetUserBUDataPermissionResponseDto getUserBUDataPermission(DataPermissionType filterType, UUID BUGUID) {
        PermType permType = getPermType(filterType);
        GetUserBUDataPermissionResponseDto getUserBUDataPermissionResponseDto = new GetUserBUDataPermissionResponseDto();

        QueryWrapper<PermBU> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("BUGUID", BUGUID);
        queryWrapper.eq("PermTypeGUID", permType.getPermTypeGUID());
        queryWrapper.last("limit 1");

        PermBU permBUS = permBUDao.selectOne(queryWrapper);
        if (permBUS == null) {
            getUserBUDataPermissionResponseDto.setExistBUPermission(false);
            return getUserBUDataPermissionResponseDto;
        }
        getUserBUDataPermissionResponseDto.setArea(permBUS.getFilterValue());

        QueryWrapper<PermUser> queryWrapperUser = new QueryWrapper<>();
        queryWrapperUser.eq("ManagedBUGUID", BUGUID);
        queryWrapperUser.eq("PermTypeGUID", permType.getPermTypeGUID());

        List<PermUser> permUserList = permUserDao.selectList(queryWrapperUser);
        List<UUID> usersGUID = permUserList.stream().map(PermUser::getUserGUID).collect(Collectors.toList());

        getUserBUDataPermissionResponseDto.setUsers(usersGUID);
        return getUserBUDataPermissionResponseDto;
    }

    // 获取用户有权益的地区,如果没有权益,返回空数组,如果有全国权益,返回 String["0"]
    public GetUserAreaPermissionResponseDto getUserPermissionArea() {
        ContextInfo contextInfo = contextManager.fetchContextInfo();
        String userId = contextInfo.getUserContext().getUserId().toString();
        GetUserAreaPermissionResponseDto response = new GetUserAreaPermissionResponseDto();

//        userId = "4230bc6e-69e6-46a9-a39e-b929a06a84e8";
        String[] selectFields = {};
        String[][] wheres = {{"eq", "UserId", userId}};
        RequestDto requestDto = QueryParamUtil.BuildRequestDto(selectFields, wheres, 0, 1000);

        ResponseDto resList = remoteSystemIBasicPublicService.QueryUserBusinessUnitMappingList(requestDto);
        if (resList == null) {
            return response;
        }
        List<String> areas = new ArrayList<>();

        resList.getResults().forEach(user -> {
            PermType permType = getPermType(DataPermissionService.DataPermissionType.CustomerClue);
            QueryWrapper<PermBU> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("BUGUID", user.getBUGUID());
            queryWrapper.eq("PermTypeGUID", permType.getPermTypeGUID());

            List<PermBU> permBUs = permBUDao.selectList(queryWrapper);
            if (permBUs != null && permBUs.size() > 0) {
                permBUs.forEach(item -> {
                    String[] area = item.getFilterValue().split(",");

                    areas.addAll(Arrays.asList(area));
                });
            }
        });

        // 如果有全国权益,返回 String["0"]
        if (areas.contains("0")) {
            ArrayList<String> area = new ArrayList<>();
            area.add("0");
            response.setArea(area);
            return response;
        }

        // areas里边既有省份也有城市
        response.setArea(areas);
        return response;
    }

    public ImportUserBUDataPermissionResponseDto importUserBUDataPermission(ImportUserBUDataPermissionRequestDto requestDto) throws IOException {
        // 判断文件是否存在
        String fileUrl = documentProvider.getDownloadUrl(requestDto.getDocumentId());
        // 读取 excel 内容
        URL url = new URL(fileUrl);
        InputStream in = url.openStream();
        List<Map<Integer, String>> importData = EasyExcel.read(in).sheet().doReadSync();
        in.close();

        int rowCount = importData.size() - 3;
        if (rowCount < 0) {
            rowCount = 0;
        }

        ImportUserBUDataPermissionResponseDto responseDto = new ImportUserBUDataPermissionResponseDto();

        ArrayList<String> failedMsg = new ArrayList<>();
        ArrayList<String> succeedMsg = new ArrayList<>();

        String[] selectFields = {};
        String[][] wheres = {};
        RequestDto queryDto = QueryParamUtil.BuildRequestDto(selectFields, wheres, 0, 1000);
        QueryOrganizationResponseDto resList = remoteSystemIBasicPublicService.QueryOrganizationList(queryDto);
        if (resList == null || resList.getResults() == null || resList.getResults().size() == 0) {
            failedMsg.add("组织架构不存在，导入失败");
            responseDto.setFailedMsg(failedMsg);
            responseDto.setFailedCount(rowCount);
            return responseDto;
        }
        if (rowCount > 1003) {
            failedMsg.add("导入数据量超过1000条，导入失败");
            responseDto.setFailedMsg(failedMsg);
            responseDto.setFailedCount(rowCount);
            return responseDto;
        }

        Map<String, String> BuName2GUID = new HashMap<>();
        resList.getResults().forEach(organizationDto -> {
            // bu简称和全称，都存到map里
            BuName2GUID.put(organizationDto.getBUName(), organizationDto.getBUGUID());
            BuName2GUID.put(organizationDto.getBUFullName(), organizationDto.getBUGUID());
            // bu的全称是用 " - " 拼接起来的，用户导入的文件中，输入的是 "-"拼接的
            BuName2GUID.put(organizationDto.getBUFullName().replaceAll(" - ", "-"), organizationDto.getBUGUID());
        });

        System.out.println("读取组织架构数据：" + JSON.toJSONString(resList));
        //resList.getResults()

        // 获取全部地区
        List<AreaDto> areaAllList = remoteAreaService.getAll();
        if (areaAllList == null || areaAllList.size() == 0) {
            failedMsg.add("获取地区信息失败，导入失败");
            responseDto.setFailedMsg(failedMsg);
            responseDto.setFailedCount(rowCount);
            return responseDto;
        }

        Map<String, String> provinceName2CodeMap = new HashMap<>();
        Map<String, String> cityName2CodeMap = new HashMap<>();
        Map<String, String> childCode2ParentCode = new HashMap<>();

        areaAllList.forEach(areaDto -> {
            if (areaDto.getParentCode().equals("0")) {
                provinceName2CodeMap.put(areaDto.getItemName(), areaDto.getItemCode());
            } else {
                cityName2CodeMap.put(areaDto.getItemName(), areaDto.getItemCode());
            }
            childCode2ParentCode.put(areaDto.getItemCode(), areaDto.getParentCode());
        });

        // 获取当前租户有权益的地址
        boolean isNationWide = false;
        List<String> profitProvinceCode = new ArrayList<>();
        GetProfitProvinceDataDto getProfitProvinceDataDto = remoteProfitService.getProfitProvince();
        if (getProfitProvinceDataDto == null) {
            failedMsg.add("获取租户权益地区信息失败，导入失败");
            responseDto.setFailedMsg(failedMsg);
            responseDto.setFailedCount(rowCount);
            return responseDto;
        }


        if (getProfitProvinceDataDto.getProvinceNumType().equals(RemoteProfitService.ProvinceNumType.NationWide.toString())) {
            //全国版的权益
            isNationWide = true;
        } else {
            if (getProfitProvinceDataDto.getProvinceList() == null ||
                    getProfitProvinceDataDto.getProvinceList().size() == 0) {
                failedMsg.add("获取租户权益省份地区信息失败，导入失败");
                responseDto.setFailedMsg(failedMsg);
                responseDto.setFailedCount(rowCount);
                return responseDto;
            }
            profitProvinceCode = getProfitProvinceDataDto.getProvinceCodeList();
        }

//        for (Map<Integer, String> data : importData) {
//            System.out.println("读取到数据：" + JSON.toJSONString(data));
//        }
        //汇总组织的区域和负责人信息，key是BUGUID，value分别是区域code集合、负责人UserGUID集合
        Map<String, HashSet<String>> summaryAreaData = new HashMap<>();
        Map<String, HashSet<String>> summaryManagerData = new HashMap<>();

        boolean hasRealData = false; //是否读到了真实的用户提交数据
        int titleCount = 0;//title出现的次数，模板文件中，title行出现了2次
        for (Map<Integer, String> data : importData) {
            if (titleCount < 2 && data.get(0) != null && data.get(0).equals("组织（必填项）") &&
                    data.get(1) != null && data.get(1).equals("负责区域（必填项）") &&
                    data.get(2) != null && data.get(2).equals("区域负责人（必填项）") &&
                    data.get(3) != null && data.get(3).equals("负责人账号")) {
                titleCount++;
                continue;
            }

            if (titleCount < 2) {
                // 非用户输入的真实有效的数据
                continue;
            }

            hasRealData = true;
            String organizationName = data.get(0) != null ? data.get(0) : "";
            String areaNames = data.get(1) != null ? data.get(1) : "";
            String chargeUserNames = data.get(2) != null ? data.get(2) : "";
            String chargeUserAccount = data.get(3) != null ? data.get(3) : "";

            // 检查必填项是否填写
            if (organizationName.equals("") || areaNames.equals("") || chargeUserNames.equals("")) {
                //必填项没有填，记录错误
                failedMsg.add(String.format("【%s】-【%s】-【%s】必填项未填，本行记录导入失败", organizationName, areaNames, chargeUserNames));
                continue;
            }
            // 检查bu是否存在
            String BUGUID = BuName2GUID.get(organizationName);
            if (BUGUID == null) {
                if (organizationName.contains("-")) {
                    String lastOrganizationName = organizationName.split("-")[organizationName.split("-").length - 1];
                    BUGUID = BuName2GUID.get(lastOrganizationName);
                    if (BUGUID == null) {
                        failedMsg.add(String.format("【%s】-【%s】-【%s】组织不存在，本行记录导入失败", organizationName, areaNames, chargeUserNames));
                        continue;
                    }
                } else {
                    failedMsg.add(String.format("【%s】-【%s】-【%s】组织不存在，本行记录导入失败", organizationName, areaNames, chargeUserNames));
                    continue;
                }
            }


            HashSet<String> curBUAreaCodeSet = new HashSet<>(); //当前配置的区域权限
            HashSet<String> curManagerSet = new HashSet<>(); //当前配置的负责人
            if (summaryAreaData.get(BUGUID) != null && summaryManagerData.get(BUGUID) != null) {
                curBUAreaCodeSet = summaryAreaData.get(BUGUID);
                curManagerSet = summaryManagerData.get(BUGUID);
            } else {
                //查看数据库中bu的现有权益权限和负责人配置
                PermType permType = getPermType(DataPermissionService.DataPermissionType.CustomerClue);
                QueryWrapper<PermBU> queryWrapper = new QueryWrapper<>();
                queryWrapper.eq("BUGUID", BUGUID);
                queryWrapper.eq("PermTypeGUID", permType.getPermTypeGUID());

                List<PermBU> permBUs = permBUDao.selectList(queryWrapper);
                if (permBUs != null && permBUs.size() > 0) {
                    for (PermBU permBU : permBUs) {
                        curBUAreaCodeSet.addAll(Arrays.asList(permBU.getFilterValue().split(",")));
                    }
                }
                QueryWrapper<PermUser> queryUserWrapper = new QueryWrapper<>();
                queryUserWrapper.eq("ManagedBUGUID", BUGUID);
                List<PermUser> permUsers = permUserDao.selectList(queryUserWrapper);
                if (permUsers != null && permUsers.size() > 0) {
                    for (PermUser permUser : permUsers) {
                        curManagerSet.add(permUser.getUserGUID().toString());
                    }
                }
            }

            // 检查地区是否在权益区域内
            String[] inputAreaNameList = areaNames.split("、");
            HashSet<String> inputAreaCodeSet = new HashSet<>();
            HashSet<String> inputProvinceCodeSet = new HashSet<>();

            boolean hasNationErr = false;
            for (String areaName : inputAreaNameList) {
                if (areaName.equals("全国")) {
                    if (!isNationWide) {
                        hasNationErr = true;
                        break;
                    }
                    inputAreaCodeSet.add("0");
                    break;
                }
                String provinceCode = provinceName2CodeMap.get(areaName);
                if (provinceCode != null && !provinceCode.equals("") && !inputAreaCodeSet.contains(provinceCode)) {
                    inputAreaCodeSet.add(provinceCode);
                    inputProvinceCodeSet.add(provinceCode);
                } else {
                    String cityCode = cityName2CodeMap.get(areaName);
                    if (cityCode != null && !cityCode.equals("") && !inputAreaCodeSet.contains(cityCode)) {
                        inputAreaCodeSet.add(cityCode);
                        String parentCode = childCode2ParentCode.get(cityCode);
                        if (parentCode != null && !parentCode.equals("")) {
                            inputProvinceCodeSet.add(parentCode);
                        }
                    }
                }
            }
            if (hasNationErr) {
                failedMsg.add(String.format("【%s】-【%s】-【%s】无全国版权益，本行记录导入失败", organizationName, areaNames, chargeUserNames));
                continue;
            }
            if (inputAreaCodeSet.isEmpty()) {
                failedMsg.add(String.format("【%s】-【%s】-【%s】输入地区不存在，本行记录导入失败", organizationName, areaNames, chargeUserNames));
                continue;
            }

            // 检查地区是否在权益区域内
            if (!isNationWide) {
                boolean hasNoPermissionArea = false;
                for (String inputProvinceCode : inputProvinceCodeSet) {
                    if (!profitProvinceCode.contains(inputProvinceCode)) {
                        failedMsg.add(String.format("【%s】-【%s】-【%s】输入地区存在非权益地区，本行记录导入失败", organizationName, areaNames, chargeUserNames));
                        hasNoPermissionArea = true;
                        break;
                    }
                }
                if (hasNoPermissionArea) {
                    continue;
                }
            }


            // 检查用户是否存在，是否重复
            String[] inputChargeUserNameList = chargeUserNames.split("、");
            wheres = new String[][]{{"in", "UserName", String.join(",", inputChargeUserNameList)}};
            queryDto = QueryParamUtil.BuildRequestDto(selectFields, wheres, 0, 9999);
            QueryUserResponseDto userList = remoteSystemIBasicPublicService.QueryUserList(queryDto);
            if (userList == null || userList.getResults() == null || userList.getResults().size() == 0) {
                failedMsg.add(String.format("【%s】-【%s】-【%s】用户不存在，本行记录导入失败", organizationName, areaNames, chargeUserNames));
                continue;
            }

            String[] inputAccountList = chargeUserAccount.split("、");

            HashMap<String, String> userName2Guid = new HashMap<>();
            userList.getResults().forEach(userDto -> {
                if (userName2Guid.get(userDto.getUserName()) == null) {
                    userName2Guid.put(userDto.getUserName(), userDto.getUserGUID());
                } else {
                    //负责人重复了,看有没有提供账号，有账号则以账号为准
                    if (Arrays.asList(inputAccountList).contains(userDto.getUserCode())) {
                        userName2Guid.put(userDto.getUserName(), userDto.getUserGUID());
                    }
                }
            });

            //将新增进来的区域添加到curBUAreas中
            curBUAreaCodeSet.addAll(inputAreaCodeSet);
            //遍历所有地区code,如果城市所在的省份已经在集合中,那么只需要保留省份就好了,把城市code从集合中移除
            HashSet<String> finalCurBUAreaCodeSet = new HashSet<>(curBUAreaCodeSet);
            curBUAreaCodeSet.forEach(code -> {
                String parentCode = childCode2ParentCode.get(code);
                if (parentCode != null && !parentCode.equals("") && finalCurBUAreaCodeSet.contains(parentCode)) {
                    finalCurBUAreaCodeSet.remove(code);
                }
            });
            for (String s : userName2Guid.keySet()) {
                curManagerSet.add(userName2Guid.get(s));
            }
            summaryAreaData.put(BUGUID, finalCurBUAreaCodeSet);
            summaryManagerData.put(BUGUID, curManagerSet);
            succeedMsg.add(String.format("【%s】-【%s】-【%s】导入成功", organizationName, areaNames, chargeUserNames));
        }

        if (titleCount < 2) {
            failedMsg.add("模板文件格式被修改,导入失败");
            responseDto.setFailedMsg(failedMsg);
            responseDto.setFailedCount(rowCount);
            return responseDto;
        }

        if (!hasRealData) {
            //空模板文件
            failedMsg.add("模板文件内容为空,或模板文件格式被修改,导入失败");
            responseDto.setFailedMsg(failedMsg);
            responseDto.setFailedCount(rowCount);
            return responseDto;
        }

        // 将汇总数据写入
        for (String buGUID : summaryAreaData.keySet()) {
            HashSet<String> areas = summaryAreaData.get(buGUID);
            HashSet<String> managers = summaryManagerData.get(buGUID);

            if (areas.isEmpty() || managers.isEmpty()) {
                //数据为空,不写入
                continue;
            }
            if (areas.contains("0")) {
                //如果区域包含全国，那么只需要保留全国即可
                areas.clear();
                areas.add("0");
            }

            List<UUID> userGUIDList = new ArrayList<>();
            managers.forEach(UserGUID -> {
                userGUIDList.add(UUID.fromString(UserGUID));
            });
            this.saveUserBUDataPermission(DataPermissionService.DataPermissionType.CustomerClue,
                    UUID.fromString(buGUID),
                    DataPermissionService.BUDataPermissionType.Area,
                    String.join(",", areas), userGUIDList);
        }

        responseDto.setFailedMsg(failedMsg);
        responseDto.setSucceedMsg(succeedMsg);
        responseDto.setSucceedCount(succeedMsg.size());
        responseDto.setFailedCount(failedMsg.size());
        return responseDto;
    }
}
